
#include <QGridLayout>
#include <QLabel>
#include <QTimer>
#include <QInputDialog>
#include <QTableWidget>
#include <QMessageBox>

#include "widget.h"
#include "window.h"
#include "blink.h"
#include "Sleeper.h"

Window::Window()
{
    setWindowTitle(tr("Simulator"));

    //KbMouse *kbm = &kbmouse;
    P8x32a  *mio = &micro;
    P8x32aDebugger *dbp = &debugger;
    Runner *runp = &run;

    display = &clock;
    display->setVisible(false);

    QGridLayout *layout = new QGridLayout;
    layout->addWidget(display, 0, 0);
    layout->addWidget(dbp, 0, 0);
    layout->addWidget(mio, 1, 0);
    // Enable keyboard later after connecting pins.
    // layout->addWidget(kbm, 2, 0);
    setLayout(layout);

//  Enable timer later after connecting video circuits.
#ifdef ENABLE_DISPLAY
    displayTimer = new QTimer(this);
    connect(displayTimer, SIGNAL(timeout()), display, SLOT(animate()));
    displayTimer->start(Widget::RunDelay);
#endif

    connect(runp,SIGNAL(execute()),&micro,SLOT(execute()));
    connect(mio,SIGNAL(stopRunner()),runp,SLOT(stop()));
    connect(mio,SIGNAL(setCogPC(int,int)),dbp,SLOT(setCogPC(int,int)));
    connect(mio,SIGNAL(showCogTab(int)),dbp,SLOT(showCogTab(int)));
    connect(mio,SIGNAL(clearBreakpoints(int)),dbp,SLOT(clearBreakpoints(int)));
    connect(mio,SIGNAL(showBreakpoint(int,int)),dbp,SLOT(showBreakpoint(int,int)));
    connect(mio,SIGNAL(clearCogMem(int)),dbp,SLOT(clearCogMem(int)));
    connect(mio,SIGNAL(showCog(int,CogInfo*)),dbp,SLOT(showCog(int,CogInfo*)));
    connect(mio,SIGNAL(clearHubMem()),dbp,SLOT(clearHubMem()));
    connect(mio,SIGNAL(pokeHubMem(int,int,int)),dbp,SLOT(pokeHubMem(int,int,int)));
    connect(mio,SIGNAL(showHubMem(uchar*,int)),dbp,SLOT(showHubMem(uchar*,int)));
    connect(mio,SIGNAL(addCogInstructions(int,QList<uint>)),dbp,SLOT(addCogInstructions(int,QList<uint>)));

    running = false;

    // debug only
    micro.initialize();
    micro.load(blink_array, sizeof(blink_array));

    for(int n = 0; n < P8x32a::COGCOUNT; n++) {
        P8x32aCogPanel *ptr = dbp->cogPointer(n);
        connect(ptr,SIGNAL(setBreakpoint(int,int)),mio,SLOT(setBreakpoint(int,int)));
        connect(ptr,SIGNAL(clearBreakpoint(int,int)),mio,SLOT(clearBreakpoint(int,int)));
    }
}

void Window::cont()
{
    run.cont();
}

void Window::delay()
{
    bool ok;
    QString text;

    text = QInputDialog::getText(this,
            tr("Animate Delay"),tr("Enter millisecond step delay:"),
            QLineEdit::Normal, run.delayStr(), &ok);

    if(ok && !text.isEmpty()) {
        int delay = text.toInt(&ok);
        if(ok) {
            /*
            if(delay < 5) {
                delay = 5;
                QMessageBox::information(this,tr("Delay too small"),tr("Using delay < 5ms can make the program unresponsive. Setting 5ms delay."));
            }
            */
            if(delay < 1) delay = 1;

            run.setDelay(delay);
        }
    }
}

void Window::clearBreakpoints()
{
    micro.clearBreakpoints();
}


void Window::showBreakpoints()
{
    micro.showBreakpoints();
}

void Window::newBreak(bool enable)
{
    micro.newCoreBreak(enable);
}

void Window::debug()
{
    debugger.setVisible(true);
    display->setVisible(false);
    micro.boot();
    micro.setDebugCycleMode(true);
    //run.start();
    running = true;
    run.setRunning(true);
    while(run.running()) {
        micro.execute();
        Sleeper::msec(run.delay());
        QApplication::processEvents();
    }
}

void Window::load(QByteArray b)
{
    display->setVisible(false);
#ifdef ENABLE_DISPLAY
    displayTimer->stop();
#endif
    micro.load(b.data(), b.size());
}

void Window::reset()
{
    display->setVisible(false);
    micro.initialize();
#ifdef ENABLE_DISPLAY
    displayTimer->stop();
#endif
}

void Window::start()
{
    debugger.setVisible(false);
    display->setVisible(true);
    micro.boot();
    micro.setDebugCycleMode(false);
#ifdef ENABLE_DISPLAY
    displayTimer->start(Widget::RunDelay);
#endif
    running = true;
    while(running) {
        micro.run();
        QApplication::processEvents();
    }
    micro.execute();
}

void Window::stop()
{
    debugger.setVisible(true);
    display->setVisible(false);
#ifdef ENABLE_DISPLAY
    displayTimer->stop();
#endif
    run.stop();
    if(running) {
        running = false;
        micro.updateState();
        // show where we are. where to stop is arbitrary for run.
        run.step();
    }
}

void Window::step()
{
    display->setVisible(false);
    micro.boot();
    run.step();
}

void Window::showTrace(bool visible)
{
    micro.showTrace(visible);
}
